/*
** Copyright (C) 2010 Calin Radoni
**
** This file is part of CHScanner.
**
** CHScanner is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** CHScanner is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with CHScanner. If not, see <http://www.gnu.org/licenses/>.
*/

#include "StdAfx.h"
#include ".\meventlog.h"

MEventLog::MEventLog(LPTSTR applicationNameIn)
{
	applicationName = applicationNameIn;
}

MEventLog::~MEventLog(void)
{
}

bool MEventLog::RegisterThisAppAsSource(DWORD categCountIn)
{
	DWORD res;
	TCHAR msgFileName[MAX_PATH];

	res = GetModuleFileName(NULL, msgFileName, MAX_PATH);
	if(res==0) return false;

	return RegisterAsSource(msgFileName, categCountIn);
}

bool MEventLog::RegisterAsSource(LPTSTR msgFileName, DWORD categCountIn)
{
	int   res;
	HKEY  key;
	LONG  lres;
	DWORD supportedEvents;

	res = _sctprintf(_T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s"), applicationName);
	if(res>MAX_PATH)
		return false;

	res = _stprintf_s(buffer, MAX_PATH, _T("SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\%s"), applicationName);
	if(res==-1)
		return false;

	lres = RegCreateKey(HKEY_LOCAL_MACHINE, buffer, &key);
	if(lres!=ERROR_SUCCESS)
		return false;

    lres = RegSetValueEx(
			key,
            _T("EventMessageFile"),
            0,
            REG_EXPAND_SZ,
            (LPBYTE)msgFileName,
            (DWORD)(_tcslen(msgFileName) + 1));
	if(lres!=ERROR_SUCCESS){
		RegCloseKey(key);
		return false;
	}

    supportedEvents = EVENTLOG_SUCCESS | EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; 
 
	lres = RegSetValueEx(
			key,
            _T("TypesSupported"),
            0,
            REG_DWORD,
            (LPBYTE)&supportedEvents,
            sizeof(DWORD));
	if(lres!=ERROR_SUCCESS){
		RegCloseKey(key);
		return false;
	}

	if(categCountIn>0){
		// register categories
		// Categories should have the message id ranging from 1 -> CategoryCount
	    lres = RegSetValueEx(
				key,
			    _T("CategoryMessageFile"),
				0,
				REG_EXPAND_SZ,
				(LPBYTE)msgFileName,
				(DWORD)(_tcslen(msgFileName) + 1));
		if(lres!=ERROR_SUCCESS){
			RegCloseKey(key);
			return false;
		}

		lres = RegSetValueEx(
				key,
			    _T("CategoryCount"),
				0,
				REG_DWORD,
				(LPBYTE)&categCountIn,
				sizeof(DWORD));
		if(lres!=ERROR_SUCCESS){
			RegCloseKey(key);
			return false;
		}
	}
 
    RegCloseKey(key); 
	return true;
}

bool MEventLog::ReportAnEvent(WORD type, WORD category, DWORD eventId, ...)
{
	int     stringCount;
	LPCTSTR *strings;
	bool    done;
	char    *ptr;
	va_list args;
	HANDLE  hEventLog;
	PSID    userSid;
	BOOL    res;

	// compute the number of strings
	va_start(args, eventId);
	done = false;
	stringCount = 0;
	while(!done){
		ptr = va_arg(args, char*);
		if(*ptr == '\0')
			done = true;
		else
			stringCount++;
	}
	va_end(args);

	// get user SID
	userSid = mws.CreateUserSID();
	if(!mws.IsValidSID(userSid)){
		if(userSid!=NULL){
			mws.DestroyUserSID(userSid);
			userSid = NULL;
		}
	}

	// register the event source
	hEventLog = RegisterEventSource(NULL, applicationName);
	if(hEventLog==NULL){
		if(userSid!=NULL)
			mws.DestroyUserSID(userSid);
		return false;
	}

	// report the event
	va_start(args, eventId);
	strings = (LPCTSTR*)args;
	res = ReportEvent(hEventLog, type, category, eventId, userSid, stringCount, 0, strings, NULL);
	va_end(args);
	if(res==0){
		DeregisterEventSource(hEventLog);
		if(userSid!=NULL)
			mws.DestroyUserSID(userSid);
		return false;
	}

	// deregister the event source
	DeregisterEventSource(hEventLog);
	if(userSid!=NULL)
		mws.DestroyUserSID(userSid);
	return true;
}

bool MEventLog::ReportAnEventWithData(WORD type, WORD category, DWORD eventId, DWORD dataSize, LPVOID data, ...){
	int     stringCount;
	LPCTSTR *strings;
	bool    done;
	char    *ptr;
	va_list args;
	HANDLE  hEventLog;
	PSID    userSid;
	BOOL    res;

	// compute the number of strings
	va_start(args, data);
	done = false;
	stringCount = 0;
	while(!done){
		ptr = va_arg(args, char*);
		if(*ptr == '\0')
			done = true;
		else
			stringCount++;
	}
	va_end(args);

	// get user SID
	userSid = mws.CreateUserSID();
	if(!mws.IsValidSID(userSid)){
		if(userSid!=NULL){
			mws.DestroyUserSID(userSid);
			userSid = NULL;
		}
	}

	// register the event source
	hEventLog = RegisterEventSource(NULL, applicationName);
	if(hEventLog==NULL){
		if(userSid!=NULL)
			mws.DestroyUserSID(userSid);
		return false;
	}

	// report the event
	va_start(args, data);
	strings = (LPCTSTR*)args;
	res = ReportEvent(hEventLog, type, category, eventId, userSid, stringCount, dataSize, strings, data);
	va_end(args);
	if(res==0){
		DeregisterEventSource(hEventLog);
		if(userSid!=NULL)
			mws.DestroyUserSID(userSid);
		return false;
	}

	// deregister the event source
	DeregisterEventSource(hEventLog);
	if(userSid!=NULL)
		mws.DestroyUserSID(userSid);
	return true;
}

// ----------------------------------------------------------------------------

HANDLE MEventLog::OpenAnEventLog(LPCTSTR machineNameIn, LPCTSTR logNameIn)
{
	HANDLE retVal;

	retVal = OpenEventLog(machineNameIn, logNameIn);
	return retVal;
}

bool MEventLog::ReadNextEventLogEntry(HANDLE eventLogHandle, LPCTSTR machineNameIn, MEventLogRecord* melr)
{
	BYTE  data[1024];
	BYTE  *highData;
	BYTE  *elrData;
	BOOL  res;
	DWORD size, readed, needed, err;

	if(eventLogHandle==NULL) return false;
	if(melr==NULL) return false;

	SecureZeroMemory(data, 1024);
	highData = NULL;

	size = 0;
	res = ReadEventLog(eventLogHandle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, 0, data, size, &readed, &needed);
	if(res) return NULL;

	err = GetLastError();
	if(err!=ERROR_INSUFFICIENT_BUFFER) return NULL;

	if(needed>1024){
		try{
			highData = new BYTE[needed];
		}
		catch(...){
			highData = NULL;
		}
		if(highData==NULL)
			return false;

		elrData = highData;
	}
	else{
		elrData = data;
	}

	size = needed;
	res = ReadEventLog(eventLogHandle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, 0, elrData, size, &readed, &needed);
	if(!res){
		if(highData!=NULL)
			delete[] highData;
		return false;
	}

	melr->Set(machineNameIn, elrData, readed);

	if(highData!=NULL)
		delete[] highData;

	return true;
}

bool MEventLog::ClearAnEventLog(HANDLE eventLogHandle, LPCTSTR backupFileName)
{
	BOOL res;

	if(eventLogHandle==NULL) return false;

	res = ClearEventLog(eventLogHandle, backupFileName);
	return res ? true : false;
}

bool MEventLog::CloseAnEventLog(HANDLE eventLogHandle)
{
	BOOL res;

	if(eventLogHandle==NULL) return true;
	
	res = CloseEventLog(eventLogHandle);
	return res ? true : false;
}
// ----------------------------------------------------------------------------
